package com.mg.plugin.agrometeorology.model;

import com.mg.model.Model;
import com.mg.model.Param;
import com.mg.model.Port;
import com.mg.plugin.agrometeorology.entity.WeaData;
import com.mg.pluginexample2.ModuleBase;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class ProductionForecastBaseSuitabilityModel extends ModuleBase {

    public ProductionForecastBaseSuitabilityModel(int nID) {
        super(nID);
        m_alInputPort.add(new Port(this, Port.Type.Unknown));
        m_alInputPort.add(new Port(this, Port.Type.Unknown));
        m_alOutputPort.add(new Port(this, Port.Type.Unknown));
    }

    public String GetGroupName() {
        return "产量预报";
    }

    public String GetName() {
        return "基于气象适宜度方法（计算）";
    }

    public String GetDescription() {
        return "基于气象适宜度方法（数据必须是同一年的）";
    }

    public boolean OnAttach(Port portFrom, Port portTo) {
        try {
            int i = FindPort(portFrom, false);
            if (i != -1) {
                return true;
            }
            i = FindPort(portTo, true);
            if (i == -1) {
                return false;
            }

            ArrayList<Param> alParam = new ArrayList<Param>();
            portFrom.GetModule().GetOutputParam(portFrom, alParam);

            if (alParam.size() != 1) {
                return false;
            }

            if (alParam.get(0).m_objValue != null && !(alParam.get(0).m_objValue instanceof ArrayList)) {
                m_model.OutputLog(Model.LogLevel.Info, "alParam.get(0).m_objValue != null && !(alParam.get(0).m_objValue instanceof ArrayList)");
                return false;
            }
            if (i == 0) {
                m_model.OutputLog(Model.LogLevel.Info, "SET m_inputStationDataList");
                m_inputStationDataList = (List<String>) alParam.get(0).m_objValue;
            }
            if (i == 1) {
                m_model.OutputLog(Model.LogLevel.Info, "m_inputRealityList" + alParam.get(0).m_objValue.getClass());
                m_inputRealityList = (List<String>) alParam.get(0).m_objValue;
            }

            portTo.SetType(portFrom.GetType());
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean OnDetach(Port portFrom, Port portTo) {
        if (!super.OnDetach(portFrom, portTo))
            return false;
        try {
            int i = FindPort(portTo, true);
            if (i == -1)
                return true;
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    //用于 参数->XML 等
    public int GetParam(ArrayList<Param> alParam) {
        try {
            super.GetParam(alParam);
            alParam.add(new Param("Date", m_strDate, "时间对应字段", "Date", "参数匹配", Param.EditType.Default));
            alParam.add(new Param("BeanSuit", m_strBeanSuit, "大豆气象适宜度", "BeanSuit", "参数匹配", Param.EditType.Default));
            alParam.add(new Param("CornSuit", m_strCornSuit, "玉米气象适宜度", "CornSuit", "参数匹配", Param.EditType.Default));
            alParam.add(new Param("RiceSuit", m_strRiceSuit, "水稻气象适宜度", "RiceSuit", "参数匹配", Param.EditType.Default));
            alParam.add(new Param("Bean", m_strBean, "大豆单产", "Bean", "参数匹配", Param.EditType.Default));
            alParam.add(new Param("Corn", m_strCorn, "玉米单产", "Corn", "参数匹配", Param.EditType.Default));
            alParam.add(new Param("Rice", m_strRice, "水稻单产", "Rice", "参数匹配", Param.EditType.Default));
            alParam.add(new Param("StartTime", m_strStartTime, "数据开始时间", "Time", "时间", Param.EditType.Default));
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return alParam.size();
    }

    public boolean OnParamChanged(ArrayList<Param> alParam, int nIndex, Object objValue) {
        return super.OnParamChanged(alParam, nIndex, objValue);
    }

    //用于 XML->参数 等
    public int SetParam(final ArrayList<Param> alParam) {
        int i = super.SetParam(alParam);
        try {
            m_strDate = (String) alParam.get(i++).m_objValue;
            m_strBeanSuit = (String) alParam.get(i++).m_objValue;
            m_strCornSuit = (String) alParam.get(i++).m_objValue;
            m_strRiceSuit = (String) alParam.get(i++).m_objValue;
            m_strBean = (String) alParam.get(i++).m_objValue;
            m_strCorn = (String) alParam.get(i++).m_objValue;
            m_strRice = (String) alParam.get(i++).m_objValue;
            m_strStartTime = (String) alParam.get(i++).m_objValue;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return i;
    }

    public int GetOutputParam(Port port, ArrayList<Param> alParam) {
        int i = FindPort(port, false);
        if (i == -1) {
            return 0;
        }

        alParam.add(new Param("ResultString", m_listCSV));
        return alParam.size();
    }

    @SuppressWarnings("static-access")
    public boolean Execute() {

        if (m_inputRealityList != null && m_inputRealityList.size() >= 2) {
            m_inputRealityList.remove(1);
            m_inputRealityList.remove(0);
            m_inputStationDataList.addAll(m_inputRealityList);
        }

        m_listCSV.clear();
        String head = "endDate,totalBean,totalCorn,totalRice,beanKV,cornKV,riceKV";
        String type = "String,Double,Double,Double,Double,Double,Double";
        m_listCSV.add(head);
        m_listCSV.add(type);
        List<WeaData> weaDataList = new ArrayList<WeaData>();
        Map<String, List<WeaData>> weaDataMap = new HashMap<String, List<WeaData>>();

        SimpleDateFormat sdfYear = new SimpleDateFormat("yyyy");
        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
        String str = m_strStartTime.replace("$ThisYear", sdfYear.format(m_model.m_dateDataStart));
        str = str.replace("$DateStart", sdfDate.format(m_model.m_dateDataStart));
        m_model.OutputLog(Model.LogLevel.Info, "STR" + str);
        Calendar dateNow = Calendar.getInstance();
        setDate(dateNow, sdfDate, str);

        if (m_inputStationDataList != null && m_inputStationDataList.size() > 0) {
            String foreHeader = m_inputStationDataList.get(0);
            if (!verifyHeader(foreHeader)) {
                m_model.OutputLog(Model.LogLevel.Error, "Header Can Not Match!");
                return false;
            } else {
                formatStationData(m_inputStationDataList, foreHeader, weaDataMap, weaDataList, dateNow, sdfDate);
            }

        }

        for (WeaData weaData : weaDataList) {
            List<WeaData> data = weaDataMap.get(weaData.getMMDD());
            double[] result = calcAvgValue(data);

            weaData.setAvgBeanSuit(result[0]);
            weaData.setAvgCornSuit(result[1]);
            weaData.setAvgRiceSuit(result[2]);
            weaData.setAvgDadou(result[3]);
            weaData.setAvgYumi(result[4]);
            weaData.setAvgShuidao(result[5]);

        }

        double totalBean = 0;
        double totalCorn = 0;
        double totalRice = 0;

        for (WeaData weaData : weaDataList) {
            List<WeaData> data = weaDataMap.get(weaData.getMMDD());
            double[] result = calcRValue(data, weaData);
            weaData.setBeanRValue(result[0]);
            weaData.setCornRValue(result[1]);
            weaData.setRiceRValue(result[2]);
            totalBean += result[0];
            totalCorn += result[1];
            totalRice += result[2];
        }

        double beanKV = 0;
        double cornKV = 0;
        double riceKV = 0;

        for (WeaData weaData : weaDataList) {
            beanKV += weaData.getBeanRValue() / totalBean * weaData.getBeanSuit();
            cornKV += weaData.getCornRValue() / totalCorn * weaData.getCornSuit();
            riceKV += weaData.getRiceRValue() / totalRice * weaData.getRiceSuit();
        }

//        double[] forecastRate = calcForecastRate(tempWeaData, rainWeaData, sunWeaData);
        String data = str + "," + totalBean + "," + totalCorn + "," + totalRice
                + "," + beanKV + "," + cornKV + "," + riceKV;
        m_listCSV.add(data);
        OnParamChanged();
        return true;
    }

    private double[] calcRValue(List<WeaData> data, WeaData calWeaData) {
        double beanSuit = 0;
        double cornSuit = 0;
        double riceSuit = 0;

        double avgBean = 0;
        double avgCorn = 0;
        double avgRice = 0;

        double bean = 0;
        double corn = 0;
        double rice = 0;

        for (WeaData weaData : data) {
            beanSuit += (weaData.getBeanSuit() - calWeaData.getAvgBeanSuit()) * (weaData.getDadou() - calWeaData.getAvgDadou());
            cornSuit += (weaData.getCornSuit() - calWeaData.getAvgCornSuit()) * (weaData.getDadou() - calWeaData.getAvgDadou());
            riceSuit += (weaData.getRiceSuit() - calWeaData.getAvgRiceSuit()) * (weaData.getDadou() - calWeaData.getAvgDadou());

            avgBean += Math.pow(weaData.getBeanSuit() - calWeaData.getAvgBeanSuit(), 2);
            avgCorn += Math.pow(weaData.getCornSuit() - calWeaData.getAvgCornSuit(), 2);
            avgRice += Math.pow(weaData.getRiceSuit() - calWeaData.getAvgRiceSuit(), 2);

            bean += Math.pow(weaData.getDadou() - calWeaData.getAvgDadou(), 2);
            corn += Math.pow(weaData.getYumi() - calWeaData.getAvgYumi(), 2);
            rice += Math.pow(weaData.getShuidao() - calWeaData.getAvgShuidao(), 2);
        }
        double[] result = new double[9];
        result[0] = beanSuit / Math.sqrt(avgBean * bean);
        result[1] = cornSuit / Math.sqrt(avgCorn * corn);
        result[2] = riceSuit / Math.sqrt(avgRice * rice);
        return result;
    }

    private double[] calcAvgValue(List<WeaData> data) {
        double avgBeanSuit = 0;
        double avgCornSuit = 0;
        double avgRiceSuit = 0;
        double avgBean = 0;
        double avgCorn = 0;
        double avgRice = 0;

        for (WeaData weaData : data) {
            avgBeanSuit += weaData.getBeanSuit();
            avgCornSuit += weaData.getCornSuit();
            avgRiceSuit += weaData.getRiceSuit();
            avgBean += weaData.getDadou();
            avgCorn += weaData.getYumi();
            avgRice += weaData.getShuidao();
        }
        double[] result = new double[6];
        result[0] = avgCornSuit / data.size();
        result[1] = avgBeanSuit / data.size();
        result[2] = avgRiceSuit / data.size();
        result[3] = avgBean / data.size();
        result[4] = avgCorn / data.size();
        result[5] = avgRice / data.size();
        return result;
    }


    private void setDate(Calendar dateNow, SimpleDateFormat sdfDate, String str) {
        try {
            dateNow.setTime(sdfDate.parse(str));
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    private WeaData formatStationData(List<String> inputRealityList, String realHeader, Map<String, List<WeaData>> weaDataMap, List<WeaData> weaDataList, Calendar dateNow, SimpleDateFormat sdfDate) {
        Calendar calendar = Calendar.getInstance();
        int realDateIndex = findDataIndex(realHeader, m_strDate);
        int realBeanSuitIndex = findDataIndex(realHeader, m_strBeanSuit);
        int realCornSuitIndex = findDataIndex(realHeader, m_strCornSuit);
        int realRiceSuitIndex = findDataIndex(realHeader, m_strRiceSuit);

        int realBeanIndex = findDataIndex(realHeader, m_strBean);
        int realCornIndex = findDataIndex(realHeader, m_strCorn);
        int realRiceIndex = findDataIndex(realHeader, m_strRice);

        String date = "";
        int dayNow = dateNow.get(Calendar.DAY_OF_MONTH);
        int monthNow = dateNow.get(Calendar.MONTH);
        int yearNow = dateNow.get(Calendar.YEAR);
        for (int i = 2; i < inputRealityList.size(); i++) {
            String[] data = inputRealityList.get(i).split(",");

            date = data[realDateIndex];
            setDate(calendar, sdfDate, date);
            int day = calendar.get(Calendar.DAY_OF_MONTH);
            int month = calendar.get(Calendar.MONTH);
            int year = calendar.get(Calendar.YEAR);

            WeaData weaData = new WeaData();
            weaData.setDate(date);
            weaData.setYear(String.valueOf(year));
            weaData.setMMDD(month + "-" + day);
            weaData.setBeanSuit(Float.parseFloat(data[realBeanSuitIndex]));
            weaData.setCornSuit(Float.parseFloat(data[realCornSuitIndex]));
            weaData.setRiceSuit(Float.parseFloat(data[realRiceSuitIndex]));

            if (!data[realBeanIndex].equals("null")) {
                weaData.setDadou(Float.parseFloat(data[realBeanIndex]));
                weaData.setYumi(Float.parseFloat(data[realCornIndex]));
                weaData.setShuidao(Float.parseFloat(data[realRiceIndex]));
            }


            if (month < monthNow || (month == monthNow && day <= dayNow)) {

                if (yearNow == year) {
                    weaDataList.add(weaData);
                } else {
                    addToMap(weaDataMap, month + "-" + day, weaData);
                }
            }
        }
        return null;
    }

    private void addToMap(Map<String, List<WeaData>> weaDataMap, String date, WeaData weaData) {
        if (weaDataMap.keySet().contains(date)) {
            weaDataMap.get(date).add(weaData);
        } else {
            List<WeaData> data = new ArrayList<WeaData>();
            data.add(weaData);
            weaDataMap.put(date, data);
        }
    }

    /**
     * 表头检验
     *
     * @param realHeader 实况数据表头
     * @return
     */
    private boolean verifyHeader(String realHeader) {

        if (realHeader.contains(m_strDate) && realHeader.contains(m_strCornSuit)) {
            if (realHeader.contains(m_strBeanSuit) && realHeader.contains(m_strRiceSuit)) {
                return true;
            }
        }
        return false;
    }

    private int findDataIndex(String realHeader, String strRain) {

        String[] data = realHeader.split(",");
        for (int i = 0; i < data.length; i++) {
            if (data[i].equalsIgnoreCase(strRain)) {
                return i;
            }
        }
        return -1;
    }

    private List<String> m_inputStationDataList = new ArrayList<String>();
    private List<String> m_inputRealityList = new ArrayList<String>();
    private List<String> m_listCSV = new ArrayList<String>();

    private Map<String, WeaData> m_oldWeaDataMap1 = new HashMap<String, WeaData>();
    private Map<String, WeaData> m_oldWeaDataMap2 = new HashMap<String, WeaData>();
    private Map<String, WeaData> m_oldWeaDataMap3 = new HashMap<String, WeaData>();
    private Map<String, WeaData> m_oldWeaDataMap4 = new HashMap<String, WeaData>();

    private String m_strDate;
    private String m_strBeanSuit;
    private String m_strCornSuit;
    private String m_strRiceSuit;
    private String m_strBean;
    private String m_strCorn;
    private String m_strRice;
    private String m_strStartTime;
}
